use std::fmt::{Display, Formatter};
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Shell {
Bash,
Zsh,
Fish,
Elvish,
Powershell,
Other(String),
}
impl Display for Shell {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bash => write!(f, "bash"),
Self::Zsh => write!(f, "zsh"),
Self::Fish => write!(f, "fish"),
Self::Elvish => write!(f, "elvish"),
Self::Powershell => write!(f, "powershell"),
Self::Other(value) => write!(f, "{value}"),
}
}
}
#[cfg(feature = "clap")]
impl From<::clap_complete::Shell> for Shell {
fn from(shell: ::clap_complete::Shell) -> Self {
match shell {
::clap_complete::Shell::Bash => Self::Bash,
::clap_complete::Shell::Elvish => Self::Elvish,
::clap_complete::Shell::Fish => Self::Fish,
::clap_complete::Shell::PowerShell => Self::Powershell,
::clap_complete::Shell::Zsh => Self::Zsh,
other => Self::Other(other.to_string()),
}
}
}
#[cfg(feature = "clap")]
impl TryFrom<Shell> for ::clap_complete::Shell {
type Error = crate::Error;
fn try_from(shell: Shell) -> std::result::Result<Self, Self::Error> {
match shell {
Shell::Bash => Ok(Self::Bash),
Shell::Elvish => Ok(Self::Elvish),
Shell::Fish => Ok(Self::Fish),
Shell::Powershell => Ok(Self::PowerShell),
Shell::Zsh => Ok(Self::Zsh),
Shell::Other(value) => Err(crate::Error::UnsupportedShell(Shell::Other(value))),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileChange {
Created,
Updated,
Unchanged,
Removed,
Absent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ActivationMode {
SystemLoader,
ManagedRcBlock,
NativeDirectory,
Manual,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ActivationPolicy {
AutoManaged,
Manual,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Availability {
ActiveNow,
AvailableAfterNewShell,
AvailableAfterSource,
ManualActionRequired,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Operation {
Install,
DetectActivation,
MigrateManagedBlocks,
Uninstall,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperationEventPhase {
Started,
Succeeded,
Failed,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OperationEvent {
pub operation: Operation,
pub phase: OperationEventPhase,
pub shell: Shell,
pub program_name: String,
pub trace_id: u64,
pub target_path: Option<PathBuf>,
pub error_code: Option<&'static str>,
pub retryable: bool,
pub duration_ms: Option<u128>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FailureKind {
MissingHome,
UnsupportedShell,
InvalidTargetPath,
DefaultPathUnavailable,
CompletionTargetUnavailable,
CompletionFileUnreadable,
ProfileUnavailable,
ProfileCorrupted,
}
impl FailureKind {
pub const fn code(self) -> &'static str {
match self {
Self::MissingHome => "shellcomp.missing_home",
Self::UnsupportedShell => "shellcomp.unsupported_shell",
Self::InvalidTargetPath => "shellcomp.invalid_target_path",
Self::DefaultPathUnavailable => "shellcomp.default_path_unavailable",
Self::CompletionTargetUnavailable => "shellcomp.completion_target_unavailable",
Self::CompletionFileUnreadable => "shellcomp.completion_file_unreadable",
Self::ProfileUnavailable => "shellcomp.profile_unavailable",
Self::ProfileCorrupted => "shellcomp.profile_corrupted",
}
}
pub const fn is_retryable(self) -> bool {
matches!(
self,
Self::CompletionTargetUnavailable
| Self::CompletionFileUnreadable
| Self::ProfileUnavailable
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InstallRequest<'a> {
pub shell: Shell,
pub program_name: &'a str,
pub script: &'a [u8],
pub path_override: Option<PathBuf>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UninstallRequest<'a> {
pub shell: Shell,
pub program_name: &'a str,
pub path_override: Option<PathBuf>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LegacyManagedBlock {
pub start_marker: String,
pub end_marker: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MigrateManagedBlocksRequest<'a> {
pub shell: Shell,
pub program_name: &'a str,
pub path_override: Option<PathBuf>,
pub legacy_blocks: Vec<LegacyManagedBlock>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InstallReport {
pub shell: Shell,
pub target_path: PathBuf,
pub file_change: FileChange,
pub activation: ActivationReport,
pub affected_locations: Vec<PathBuf>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CleanupReport {
pub mode: ActivationMode,
pub change: FileChange,
pub location: Option<PathBuf>,
pub reason: Option<String>,
pub next_step: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RemoveReport {
pub shell: Shell,
pub target_path: PathBuf,
pub file_change: FileChange,
pub cleanup: CleanupReport,
pub affected_locations: Vec<PathBuf>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MigrateManagedBlocksReport {
pub shell: Shell,
pub target_path: PathBuf,
pub location: Option<PathBuf>,
pub legacy_change: FileChange,
pub managed_change: FileChange,
pub affected_locations: Vec<PathBuf>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ActivationReport {
pub mode: ActivationMode,
pub availability: Availability,
pub location: Option<PathBuf>,
pub reason: Option<String>,
pub next_step: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FailureReport {
pub operation: Operation,
pub shell: Shell,
pub target_path: Option<PathBuf>,
pub affected_locations: Vec<PathBuf>,
pub kind: FailureKind,
pub file_change: Option<FileChange>,
pub activation: Option<ActivationReport>,
pub cleanup: Option<CleanupReport>,
pub reason: String,
pub next_step: Option<String>,
pub trace_id: u64,
}
impl FailureReport {
pub const fn error_code(&self) -> &'static str {
self.kind.code()
}
pub const fn is_retryable(&self) -> bool {
self.kind.is_retryable()
}
}